
import cv2
import numpy as np
from os.path import join

datapath="CarData/TrainImages"
def path(cls,i):
    """"""
    return "%s/%s%d.pgm"%(datapath,cls,i+1)

pos,neg="pos-","neg-"

#创建两个SIFT对象，一个用来检测KeyPoint，另一个用来计算对应的描述符
#其实也可以只定义一个SIFT对象并使用detectAndCompute()函数
detect=cv2.xfeatures2d.SIFT_create()
extract = cv2.xfeatures2d.SIFT_create()

flann_params =dict(algorithm=1, trees=5)
flann =cv2.FlannBasedMatcher(flann_params,{})

#创建BOW训练器
bow_kmeans_trainer=cv2.BOWKMeansTrainer(40) #K=40,表示40个分类
extract_bow=cv2.BOWImgDescriptorExtractor(extract,flann)    #特征提取器为extract,特征匹配器为flann

#定义一个工具函数，用于从图像提取SIFT特征
def extract_sift(filename):
    im=cv2.imread(filename,cv2.IMREAD_GRAYSCALE)
    #也可以只使用单一函数detectAndCompute()
    feature = extract.compute(im,detect.detect(im))
    #sift计算结果的[0]部分是检测到的各KeyPoint，[1]为对应各KeyPoint的描述符
    return feature[1]

####到此，需要的都准备好了，开始训练BOW trainer

#从正反类中各读取8个图像进行训练
for i in range(8):
    #sift特征
    feature=extract_sift(path(pos,i))
    bow_kmeans_trainer.add(feature) #添加正例图像的描述符
    bow_kmeans_trainer.add(extract_sift(path(neg,i)))   #添加反例图像的描述符

#使用k-means分类器从训练的图像返回vocabulary
#vocabular就是各分类中心的描述符
voc = bow_kmeans_trainer.cluster()
#将vocabulary赋值给BOWImgDescriptorExtractor使得其能够从测试图像提取描述符
extract_bow.setVocabulary(voc)

#定义函数，返回由BOW描述符提取器计算的图像的vocabulary特征向量
#返回的是[[x1,x2,...,xN]]的二维数组
def bow_features(filename):
    im=cv2.imread(filename,0)
    return extract_bow.compute(im,detect.detect(im))

#创建两个数组来容纳训练数据和标签，
# 并用BOWImgDescriptorExtractor生成的特征向量填充它们
traindata,trainlabels =[],[]
for i in range(20):
    traindata.extend(bow_features(path(pos,i))); trainlabels.append(1)
    traindata.extend(bow_features(path(neg,i))); trainlabels.append(-1)

##创建SVM分类器，并填入训练数据
svm =cv2.ml.SVM_create()
#进行训练，其中ROW_SAMPLE表示每个训练数据为一行
svm.train(np.array(traindata),cv2.ml.ROW_SAMPLE, np.array(trainlabels))

#定义预测函数
def predict(filename):
    f=bow_features(filename);
    p=svm.predict(f)
    print(filename,"\t",p[1][0][0])
    return p

#载入测试图像
test0_file="misc_pic/Breaking-Bad.jpg"
test1_file="misc_pic/car.jpg"
test0_img=cv2.imread(test0_file)
test1_img=cv2.imread(test1_file)

#进行预测
test0_predict=predict(test0_file)
test1_predict=predict(test1_file)

font=cv2.FONT_HERSHEY_SIMPLEX
if (test0_predict[1][0][0]==1.0):
    cv2.putText(test0_img,'Car Detected',(10,30),font,1,(0,255,0),2,cv2.LINE_AA)
if (test1_predict[1][0][0]==1.0):
   cv2.putText(test1_img,'Car Detected',(10,30),font,1,(0,255,0),2,cv2.LINE_AA)

cv2.imshow("test0",test0_img)
cv2.imshow("test1",test1_img)

cv2.waitKey(0)
cv2.destroyAllWindows()






